package com.wu;

import com.wu.components.NettyServerHandle;
import com.wu.components.RpcDecoder;
import com.wu.components.RpcEncoder;
import com.wu.flandre_common.entity.RpcRequest;
import com.wu.flandre_common.entity.RpcResponse;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * Flandre引擎启动类
 *
 * @author 50816
 */
@Slf4j
public class AppEngine {
    private static final Integer ENGINE_PORT = 25543;
    /**
     * bossGroup就是parentGroup，是负责处理TCP/IP连接的
     */
    private EventLoopGroup bossGroup = new NioEventLoopGroup();
    /**
     * workerGroup就是childGroup,是负责处理Channel(通道)的I/O事件
     */
    private EventLoopGroup workerGroup = new NioEventLoopGroup();

    public static void main(String[] args) throws Exception {
        AppEngine appEngine = new AppEngine();
        appEngine.bind();
    }

    public void bind() throws Exception {
        ServerBootstrap sb = new ServerBootstrap();
        sb.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                //初始化服务端可连接队列,指定了队列的大小128
                .option(ChannelOption.SO_BACKLOG, 128)
                //保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                // 绑定客户端连接时候触发操作
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel sh) throws Exception {
                        sh.pipeline()
                                .addLast(new RpcDecoder(RpcRequest.class)) //解码request
                                .addLast(new RpcEncoder(RpcResponse.class)) //编码response
                                .addLast(new NettyServerHandle()); //使用ServerHandler类来处理接收到的消息
                    }
                });
        //绑定监听端口，调用sync同步阻塞方法等待绑定操作完
        ChannelFuture future = sb.bind("192.168.5.145",ENGINE_PORT).sync();

        if (future.isSuccess()) {
            log.info("服务端启动成功,端口号:{}", ENGINE_PORT);
        } else {
            log.error("服务端启动失败");
            future.cause().printStackTrace();
            //关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
        //成功绑定到端口之后,给channel增加一个 管道关闭的监听器并同步阻塞,直到channel关闭,线程才会往下执行,结束进程。
        future.channel().closeFuture().sync();
    }

    public void closeEngine() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}
